// NMemoryManagerPerfTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <assert.h>
#include <stdlib.h>

#pragma comment (lib, "Winmm.lib")


#define PERF_CHECK_START()		ULONGLONG Start = GetTickCount64();
#define PERF_CHECK_END( _tag )	ULONGLONG Elapse = GetTickCount64() - Start;	Elapse;/*printf_s( "Elapsed - " #_tag " : %d\n", Elapse );*/


void ShowUsage()
{
	printf_s( "Usage : NMemoryMangerPerfTest.exe [LoopCount] [MaxMemorySize] [StressLoopCount]\n" );
	printf_s( "LoopCount - alloc and free loop\n" );
	printf_s( "MaxMemorySize - random memory size from 1 to MaxMemorySize\n" );
	printf_s( "StressLoopCount - brutal repeat count\n" );
}


int _tmain(int argc, _TCHAR* argv[])
{
	if ( 4 != argc )
	{
		ShowUsage();
		return -1;
	}
	
	srand( timeGetTime() );

	CNMemoryManagerST* pMemoryManagerST = new CNMemoryManagerST();

	const int cnLoopCount		= _ttoi( argv[1] );// 10000;
	const int cnMaxMemSize		= _ttoi( argv[2] );// 32;
	const int cnStressLoopCount	= _ttoi( argv[3] );// 100;

	std::vector<void*> vecContainer;

	ULONGLONG ullMemoryManagerST	= 0;
	ULONGLONG ullNewDelete			= 0;

	{
		PERF_CHECK_START()

		for ( int nCur = 0; nCur < cnStressLoopCount; ++nCur )
		{
			vecContainer.clear();
			vecContainer.reserve( cnLoopCount );

			{
				// PERF_CHECK_START()

				for ( int nInnerCur = 0; nInnerCur < cnLoopCount; ++nInnerCur )
				{
					int nSize = RangedRand(1, cnMaxMemSize);

					vecContainer.push_back( pMemoryManagerST->Alloc( nSize ) );
				}

				// PERF_CHECK_END( MemoryManagerST_Alloc )
			}


			{
				// PERF_CHECK_START()

				for ( void*& pMem : vecContainer )
				{
					pMemoryManagerST->Free( pMem );
				}

				// PERF_CHECK_END( MemoryManagerST_Free )
			}
		}

		PERF_CHECK_END( MemoryManagerST );

		ullMemoryManagerST = Elapse;
	}

	SAFE_DELETE( pMemoryManagerST );


	{
		vecContainer.clear();
				
		PERF_CHECK_START()
			
		for ( int nCur = 0; nCur < cnStressLoopCount; ++nCur )
		{
			vecContainer.clear();
			vecContainer.reserve( cnLoopCount );

			{
				// PERF_CHECK_START()

				for ( int nInnerCur = 0; nInnerCur < cnLoopCount; ++nInnerCur )
				{
					int nSize = RangedRand(1, cnMaxMemSize);

					vecContainer.push_back( new char[nSize] );
				}

				// PERF_CHECK_END( NewDelete_New )
			}


			{
				// PERF_CHECK_START()

				for ( void*& pMem : vecContainer )
				{
					delete [] pMem;
				}

				// PERF_CHECK_END( NewDelete_Delete )
			}
		}
		
		PERF_CHECK_END( New Delete )

		ullNewDelete = Elapse;
	}

	printf_s( "PerfComparison - NewDelete (%I64d), MemoryMangerST (%I64d), %0.02f%% faster\n", 
				ullNewDelete, ullMemoryManagerST, (float(ullNewDelete) / float(ullMemoryManagerST)) * 100.0f );

	return 0;
}

